/*
 * #!
 * Ontopia Webed
 * #-
 * Copyright (C) 2001 - 2013 The Ontopia Project
 * #-
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * !#
 */

package net.ontopia.topicmaps.webed.impl.actions.occurrence;

import java.net.MalformedURLException;
import java.util.Iterator;

import net.ontopia.infoset.content.ContentStoreException;
import net.ontopia.infoset.content.ContentStoreIF;
import net.ontopia.infoset.content.ContentStoreUtils;
import net.ontopia.infoset.core.LocatorIF;
import net.ontopia.infoset.impl.basic.URILocator;
import net.ontopia.topicmaps.core.OccurrenceIF;
import net.ontopia.topicmaps.core.TopicIF;
import net.ontopia.topicmaps.core.TopicMapBuilderIF;
import net.ontopia.topicmaps.core.TopicMapIF;
import net.ontopia.topicmaps.query.core.InvalidQueryException;
import net.ontopia.topicmaps.query.core.QueryProcessorIF;
import net.ontopia.topicmaps.query.core.QueryResultIF;
import net.ontopia.topicmaps.query.utils.QueryUtils;
import net.ontopia.topicmaps.webed.core.ActionIF;
import net.ontopia.topicmaps.webed.core.ActionParametersIF;
import net.ontopia.topicmaps.webed.core.ActionResponseIF;
import net.ontopia.topicmaps.webed.core.ActionRuntimeException;
import net.ontopia.topicmaps.webed.core.FileValueIF;

/**
 * INTERNAL: Action for uploading a file as an external occurrence.
 *
 * @since 2.0.3
 */
public class UploadFile implements ActionIF {

  @Override
  public void perform(ActionParametersIF params, ActionResponseIF response) {

    try {
      // initialize
      OccurrenceIF occ = (OccurrenceIF) params.get(0);
      TopicMapIF tm = occ.getTopicMap();
      ContentStoreIF store = ContentStoreUtils.getContentStore(tm, null);
    
      // write content into store
      FileValueIF file = params.getFileValue();
      int key = store.add(file.getContents(), (int) file.getLength());

      // check if there already is a file there; if so, delete
      if (occ.getLocator() != null) {
        String uri = occ.getLocator().getAddress();
        if (uri.startsWith("x-ontopia:cms:") && noOtherReference(occ))
          store.remove(Integer.parseInt(uri.substring(14)));
      }
    
      // create new locator for content, put into occurrence
      LocatorIF loc = new URILocator("x-ontopia:cms:" + key);
      occ.setLocator(loc);
    
      // store filename on reifying topic
      TopicIF reifier = occ.getReifier();
      TopicIF filename = getTopicById(tm, "filename");

      OccurrenceIF occurrence = null;
      Iterator it = reifier.getOccurrences().iterator();
      while (it.hasNext()) {
        occ = (OccurrenceIF) it.next();
        if (occ.getType() != null && occ.getType().equals(filename)) {
          occurrence = occ;
          break;
        }
      }

      if (occurrence == null) { // no previously recorded filename
        TopicMapBuilderIF builder = tm.getBuilder();
        occurrence = builder.makeOccurrence(reifier, filename, file.getFileName());
      } else {
				occurrence.setValue(file.getFileName());
			}
    } catch (ContentStoreException e) {
      throw new ActionRuntimeException(e);
    } catch (MalformedURLException e) {
      throw new ActionRuntimeException(e);
    } catch (java.io.IOException e) {
      throw new ActionRuntimeException("Error when saving file to content store", e);
    }
  }

  // --- Internal methods

  private TopicIF getTopicById(TopicMapIF topicmap, String id) {
    LocatorIF base = topicmap.getStore().getBaseAddress();
    LocatorIF srcloc = base.resolveAbsolute('#' + id);
    return (TopicIF) topicmap.getObjectByItemIdentifier(srcloc);
  }

  private boolean noOtherReference(OccurrenceIF occurrence) {
    try {
      QueryProcessorIF processor =
        QueryUtils.getQueryProcessor(occurrence.getTopicMap());
      QueryResultIF result = processor.execute(
        "select $OBJ from " +
        "resource($OBJ, \"" + occurrence.getLocator().getAddress() + "\"), " +
        "$OBJ /= @" + occurrence.getObjectId() + "?");
      boolean other = result.next();
      result.close();
      return other;
    } catch (InvalidQueryException e) {
      throw new ActionRuntimeException(e);
    }
  }
  
}
